package sindconsole.auth.webapp;

import common.exception.ForbiddenException;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import sindconsole.auth.authz.MultidomainAuthorizationInfo;
import sindconsole.auth.bean.Account;
import sindconsole.auth.bean.User;
import sindconsole.auth.bean.UserPrincipal;

import java.util.List;

@Configuration
public class AuthWebapp implements WebMvcConfigurer {

    public static final String SUBJECT_USER = "subjectUser";

    public static final String SUBJECT_ACCOUNT = "subjectAccount";

    public static final String AUTHORIZED_DOMAIN_IDS = "authorizedDomainIds";

    @Autowired
    AuthRealm authRealm;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new HandlerMethodArgumentResolver() {
            @Override
            public boolean supportsParameter(MethodParameter methodParameter) {
                return User.class.isAssignableFrom(methodParameter.getParameterType()) && SUBJECT_USER.equals(methodParameter.getParameterName());
            }
            @Override
            public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) {
                Subject subject = SecurityUtils.getSubject();
                if(subject == null) throw new ForbiddenException();
                UserPrincipal principal = (UserPrincipal) subject.getPrincipal();
                if(principal == null) throw new ForbiddenException();
                return principal.getUser();
            }
        });
        argumentResolvers.add(new HandlerMethodArgumentResolver() {
            @Override
            public boolean supportsParameter(MethodParameter methodParameter) {
                return Account.class.isAssignableFrom(methodParameter.getParameterType()) && SUBJECT_ACCOUNT.equals(methodParameter.getParameterName());
            }
            @Override
            public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) {
                Subject subject = SecurityUtils.getSubject();
                if(subject == null) throw new ForbiddenException();
                UserPrincipal principal = (UserPrincipal) subject.getPrincipal();
                if(principal == null) throw new ForbiddenException();
                return principal.getAccout();
            }
        });
        argumentResolvers.add(new HandlerMethodArgumentResolver() {
            @Override
            public boolean supportsParameter(MethodParameter methodParameter) {
                return List.class.isAssignableFrom(methodParameter.getParameterType()) && AUTHORIZED_DOMAIN_IDS.equals(methodParameter.getParameterName());
            }
            @Override
            public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) {
                Subject subject = SecurityUtils.getSubject();
                if(subject == null) throw new ForbiddenException();
                MultidomainAuthorizationInfo authorizationInfo = (MultidomainAuthorizationInfo)authRealm.getAuthorizationInfo();
                if(authorizationInfo == null) throw new ForbiddenException();
                return authorizationInfo.getAuthorizedDomainIds();
            }
        });
    }

}
